﻿/**	@file		loli_ptr.hpp
 *	@date		(2007-08-02 21:00:18)/(2011-02-27 22:39:40)
 *-----------------------------------------------------------------------------
 *	@version	1.0.16.20
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__TOY__LOLI_PTR__NICK__K_IN_G__)
#define		__LOLIX__TOY__LOLI_PTR__NICK__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------

#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)

#if			!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)
	#include	"../lolix_type.h"
#endif	//	!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)

#if			!defined(__LOLIX__TOY_L_X_ASSERT_NICK__K_IN_G__)
	#include	"./lx_assert.h"
#endif	//	!defined(__LOLIX__TOY_L_X_ASSERT_NICK__K_IN_G__)

#if			!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)
	#include	"./std_v2t.hpp"
#endif	//	!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)


#if			LOLIX_CFG__IS_DEBUG
	#define		__LOLIX_TMP_MACRO_CHECK_VALID(o)	do{LOLIX_ASSERT(!(o).NO_NULL_PTR || (o).get(), "THIS CONTAIN CANN'T HANDLE NULL OBJECT PTR");}while(0)
#else	//	LOLIX_CFG__IS_DEBUG
	#define		__LOLIX_TMP_MACRO_CHECK_VALID(o)	NULL_OPT
#endif	//	LOLIX_CFG__IS_DEBUG

namespace lolix{namespace toy{

#if			LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
namespace _help{
	template<lx_u32, lx_u32, lx_u32, lx_u32>
	struct __Itf_id_proc;

	template<typename _Tx>
	type_true::value_size __Is_have_itf_id(__Itf_id_proc<_Tx::_lx_itf_id_r, _Tx::_lx_itf_id_g, _Tx::_lx_itf_id_b, _Tx::_lx_itf_id_a>*);
	template<typename _Tx>
	type_false::value_size __Is_have_itf_id(...);

	template<typename _Ty>
	class __check_for_itf
	{
	public:
		enum {is_have_itf_id = (sizeof(__Is_have_itf_id<_Ty>(0)) == sizeof(type_true::value_size))?1:0};
	};

	template<typename _THaveItfID, typename _Ty, typename _TBase>
	class __define_itf_id;

	template<typename _Ty, typename _TBase>
	class __define_itf_id<type_false, _Ty, _TBase>
		: public _TBase
	{
	};

	template<typename _Ty>
	class __define_itf_id<type_false, _Ty, void>
	{
	};

	template<typename _Ty, typename _TBase>
	class __define_itf_id<type_true, _Ty, _TBase>
		: public _TBase
	{
	public:
		LOLIX_DEFINE_ITF_ID(_Ty::_lx_itf_id_r, _Ty::_lx_itf_id_g, _Ty::_lx_itf_id_b, _Ty::_lx_itf_id_a);
	};

	template<typename _Ty>
	class __define_itf_id<type_true, _Ty, void>
	{
	public:
		LOLIX_DEFINE_ITF_ID(_Ty::_lx_itf_id_r, _Ty::_lx_itf_id_g, _Ty::_lx_itf_id_b, _Ty::_lx_itf_id_a);
	};
}
#endif	//	LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID

template<typename _Ty>
class	ptr_ref_proxy
#if			LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
	: public _help::__define_itf_id<typename type::type_choise<_help::__check_for_itf<_Ty>::is_have_itf_id, type_true, type_false>::type, _Ty, v2t_trait<_Ty> >
#else	//	LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
	: public v2t_trait<_Ty>
#endif	//	LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
{
	typedef	ptr_ref_proxy<_Ty>	this_type;
	typedef	v2t_trait<_Ty>		base_type;
public:
#if			!LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
	LOLIX_DEFINE_ITF_ID(_Ty::_lx_itf_id_r, _Ty::_lx_itf_id_g, _Ty::_lx_itf_id_b, _Ty::_lx_itf_id_a);
#endif	//	!LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
	typedef	typename base_type::const_pointer		const_pointer;
	typedef	typename base_type::const_reference		const_reference;
	typedef	typename base_type::pointer				pointer;
	typedef	typename base_type::reference			reference;
	typedef	typename base_type::value_type			element_type;

	LOLIX_INLINE_CALL static size_type inc_ref(const_pointer ptr)
		{
		return ptr->inc_ref();
		}

	LOLIX_INLINE_CALL static size_type release(const_pointer ptr)
		{
		return ptr->release();
		}
};

template<typename _Ty, bool _Vnonull = false, typename _RefProxy = ptr_ref_proxy<_Ty> >
class	loli_ptr
{
	typedef	loli_ptr<_Ty, _Vnonull, _RefProxy>	this_type;
	friend loli_ptr<_Ty, true, _RefProxy>;
	friend loli_ptr<_Ty, false, _RefProxy>;

	struct	_modi_pptr
#if			LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
		: public _help::__define_itf_id<typename type::type_choise<_help::__check_for_itf<_Ty>::is_have_itf_id, type_true, type_false>::type, _Ty, void>
#endif	//	LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
		{
#if			!LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID
		LOLIX_DEFINE_ITF_ID(_RefProxy::_lx_itf_id_r, _RefProxy::_lx_itf_id_g, _RefProxy::_lx_itf_id_b, _RefProxy::_lx_itf_id_a);
#endif	//	!LOLIX_CFG__AUTO_CHECK_HAVE_ITF_ID

		_Ty* _ptr;
		loli_ptr<_Ty, _Vnonull>& _ct;
		LOLIX_INLINE_CALL	explicit _modi_pptr(loli_ptr<_Ty, _Vnonull>& ct)
			: _ct(ct)
			, _ptr(ct._ptr)
			{
			}

		LOLIX_INLINE_CALL	~_modi_pptr(void)
			{
			if ( this->_ptr == this->_ct._ptr )
				return;

			if ( _Vnonull || this->_ptr )
				_RefProxy::release(this->_ptr);
			__LOLIX_TMP_MACRO_CHECK_VALID(_ct);
			}

		template <typename _To>
		operator _To** (void)const
			{
			DO_IN_DEBUG_MODEL(_To* xxx = _ptr);
			return (_To**)&_ct._ptr;
			}
		};
public:
	typedef	_RefProxy	proxy_type;
	typedef	typename proxy_type::const_pointer		const_pointer;
	typedef	typename proxy_type::const_reference	const_reference;
	typedef	typename proxy_type::pointer			pointer;
	typedef	typename proxy_type::reference			reference;
	typedef	typename proxy_type::element_type		element_type;
	enum	{NO_NULL_PTR = _Vnonull};

	LOLIX_INLINE_CALL	loli_ptr<_Ty, _Vnonull, _RefProxy>(void): _ptr(0){STATIC_ASSERT(!_Vnonull);}
	template<typename _To, bool _Vno>
	LOLIX_INLINE_CALL	loli_ptr<_Ty, _Vnonull, _RefProxy>( loli_ptr<_To, _Vno> o )
		: _ptr( (o.NO_NULL_PTR || o.get())? proxy_type::inc_ref(o.get()), o.get(): 0 )
		{
			__LOLIX_TMP_MACRO_CHECK_VALID(o);
		}

	LOLIX_INLINE_CALL	loli_ptr<_Ty, _Vnonull, _RefProxy>( const loli_ptr<_Ty, _Vnonull>& o )
		: _ptr( (o.NO_NULL_PTR || o._ptr)? proxy_type::inc_ref(o._ptr), o._ptr: 0 )
		{
			__LOLIX_TMP_MACRO_CHECK_VALID(o);
		}

	LOLIX_INLINE_CALL	loli_ptr<_Ty, _Vnonull, _RefProxy>( _Ty* o )
		: _ptr(o? proxy_type::inc_ref(o), o : 0)
		{
			__LOLIX_TMP_MACRO_CHECK_VALID(*this);
		}

	LOLIX_INLINE_CALL	~loli_ptr<_Ty, _Vnonull, _RefProxy>(void)
		{
		__BEGIN_DISABLE_CONSTANT_CONDITIONAL_EXPRESSION_WARNING();
		if ( NO_NULL_PTR || _ptr )
			proxy_type::release(_ptr);
		__END_DISABLE_CONSTANT_CONDITIONAL_EXPRESSION_WARNING();
		}

	template<typename _To, bool _Vno>
	LOLIX_INLINE_CALL	this_type&	operator = (loli_ptr<_To, _Vno> o)
		{
		__reset_with_check_src(o._ptr, typename lolix::type::type_choise<o.NO_NULL_PTR, lolix::type_false, lolix::type_true>::type());
		return *this;
		}

	LOLIX_INLINE_CALL	this_type&	operator = (this_type o)
		{
		__reset_with_check_src(o._ptr, typename lolix::type::type_choise<o.NO_NULL_PTR, lolix::type_false, lolix::type_true>::type());
		return *this;
		}

	LOLIX_INLINE_CALL	pointer			operator->(void)const
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	reference		operator*(void)const
		{
		return *_ptr;
		}

	LOLIX_INLINE_CALL	pointer			get(void)const
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	void	reset(_Ty* o)
		{
		return __reset_with_check_src(o, lolix::type_true());
		}

	LOLIX_INLINE_CALL	operator _Ty*(void)const
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	_modi_pptr operator& (void)
		{
		return _modi_pptr(*this);
		}

	LOLIX_INLINE_CALL	_Ty*const* operator& (void)const
		{
		return &_ptr;
		}

	LOLIX_INLINE_CALL	void	swap(this_type& o)
		{
		_Ty* tmp = o;
		o._ptr = _ptr;
		_ptr = tmp;
		}

#undef		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC
#define		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(__lx_v__)		\
			template<bool is_null>	LOLIX_INLINE_CALL	bool operator __lx_v__ (const loli_ptr<_Ty, is_null>& o)const{return _ptr __lx_v__ o._ptr;}\
			template<typename _Tx>	LOLIX_INLINE_CALL	bool operator __lx_v__ (_Tx* o)const{return _ptr __lx_v__ o;}
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(==);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(!=);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(<);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(<=);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(>);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(>=);
#undef		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC

private:
	LOLIX_INLINE_CALL	void	__reset_with_check_src(_Ty* o, lolix::type_false/*no need check null ptr*/)
		{
		proxy_type::inc_ref(o);
		return __reset_without_auto_inc_ref<false>(o);
		}
	LOLIX_INLINE_CALL	void	__reset_with_check_src(_Ty* o, lolix::type_true/* need check null ptr*/)
		{
		if ( o ) proxy_type::inc_ref(o);
		return __reset_without_auto_inc_ref<false>(o);
		}

	template<bool need_check_same_ptr>
	LOLIX_INLINE_CALL	void	__reset_without_auto_inc_ref(_Ty* o)
		{
		__BEGIN_DISABLE_CONSTANT_CONDITIONAL_EXPRESSION_WARNING();
		if ( need_check_same_ptr && o == _ptr )
			return;

		if ( NO_NULL_PTR || _ptr )
			proxy_type::release(_ptr);
		__BEGIN_DISABLE_CONSTANT_CONDITIONAL_EXPRESSION_WARNING();
		_ptr = o;
		__LOLIX_TMP_MACRO_CHECK_VALID(*this);
		}

	pointer		_ptr;
};


}}
#undef		__LOLIX_TMP_MACRO_CHECK_VALID

namespace lolix{
	template<typename _Ty, bool _Vnonull, typename _RefProxy>
	LOLIX_INLINE_CALL void swap(toy::loli_ptr<_Ty, _Vnonull, _RefProxy>& tl, toy::loli_ptr<_Ty, _Vnonull, _RefProxy>& tr)
	{ tl.swap(tr); }
}

#define		LOLI_PTR(loli_ptr_name, ptr_val)			__LOLIX_PTR_EX(false, loli_ptr_name, ptr_val)
#define		LOLI_NO_NULL_PTR(loli_ptr_name, ptr_val)	__LOLIX_PTR_EX(true, loli_ptr_name, ptr_val)

#define		LOLI_NO_NAME_PTR(ptr_val)					__LOLIX_NO_NAME_PTR_EX(false, ptr_val)
#define		LOLI_NO_NAME_NULL_PTR(ptr_val)				__LOLIX_NO_NAME_PTR_EX(true, ptr_val)

#define		__LOLIX_NO_NAME_PTR_EX(ptr_nonull, ptr_val)		__LOLIX_PTR_EX(ptr_nonull, LOLIX_RANDOM_NAME_WITH_(loli_ptr_), ptr_val)
#define		__LOLIX_PTR_EX(ptr_nonull, ptr_name, ptr_val)	::lolix::toy::loli_ptr<decltype(*ptr_val), ptr_nonull>	loli_ptr_name(ptr_val)

//STATIC_ASSERT(sizeof(lolix::toy::loli_ptr<lolix::itf>) == sizeof(void*));
//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX__TOY__LOLI_PTR__NICK__K_IN_G__)
